package com.bifrost.service.impl;

import com.bifrost.entity.*;
import com.bifrost.model.option.OptionModel;
import com.bifrost.model.option.OptionValueModel;
import com.bifrost.repository.ProductOptionRepository;
import com.bifrost.repository.ProductOptionValueRepository;
import com.bifrost.repository.ProductRepository;
import com.bifrost.service.ProductOptionService;
import com.bifrost.service.StoreService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 里昂
 * @com.bifrost.service.impl
 * @wechat-mall
 * @lee Create Class on 2018/4/9
 */
@Service
@Slf4j
public class ProductOptionServiceImpl implements ProductOptionService {

    @Autowired
    ProductOptionRepository productOptionRepository;
    @Autowired
    ProductOptionValueRepository productOptionValueRepository;
    @Autowired
    StoreService storeService;
    @Autowired
    ProductRepository productRepository;




    /**
     * 获取tree类型 规格数据
     *
     * @param optionId 规格id
     * @return
     */
    @Override
    //@Cacheable(value = "option:getOptionVlauesTree")
    public List getOptionVlauesTree(Long optionId) {
        ArrayList<OptionModel> list = new ArrayList<>();
        ProductOption productOption;
        if( optionId == null ){
            productOptionRepository.findAll().stream().forEach(option -> {
                OptionModel optionModel = convertOptionMap(option);
                list.add(optionModel);
            });
        }else{
            Assert.notNull(productOption = productOptionRepository.getOne(optionId),"没有对应的规格分类");
            OptionModel optionModel = convertOptionMap(productOption);
            list.add(optionModel);
        }

        return list;
    }


    @Override
    public OptionModel findOptionByName(String optionName) {

        ProductOption option =null;
        Assert.notNull(option = productOptionRepository.findFirstByAttributeName(optionName),"规格不存在");
        return convertOptionMap(option);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    //@CacheEvict(value = "option:getOptionVlauesTree" , allEntries = true)
    public void newOption(OptionModel optionModel) {

        // 新增规格
        ProductOption persistenceOption = productOptionRepository.findFirstByAttributeName(optionModel.getAttributeName().trim());
        Assert.isNull(persistenceOption,"规格已存在");
        optionModel.setAttributeName(optionModel.getAttributeName().trim());
        ProductOption option = new ProductOption();
        BeanUtils.copyProperties(optionModel, option);
        option.setOptionType("1");
        //TODO 设置门店
        Assert.notNull(option = productOptionRepository.save(option),"保存失败");
        List<OptionValueModel> optionValueModels = null;
        if (!CollectionUtils.isEmpty(optionValueModels = optionModel.getOptionValues())) {
            ProductOption finalOption = option;
            final ProductOptionValue[] optionValue = {null} ;
            optionValueModels.stream().forEach(optionValueModel -> {
                newOptionValue(optionValue[0],finalOption, optionValueModel);
            });
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    //@CacheEvict(value = "option:getOptionVlauesTree" , allEntries = true)
    public void mergeOption(OptionModel optionModel) {

        Long optionId = optionModel.getProductOptionId();
        Assert.notNull(optionId,"规格不存在");
        ProductOption persistenceOption = null;
        Assert.notNull(persistenceOption=productOptionRepository.findOne(optionId),"规格不存在");

        optionModel.setAttributeName(optionModel.getAttributeName().trim());
        BeanUtils.copyProperties(optionModel,persistenceOption);
        ProductOption finalPersistenceOption = productOptionRepository.save(persistenceOption);

        List<OptionValueModel> modelValues = optionModel.getOptionValues();
        //modelValues.stream().forEach(optionValueModel -> optionValueModel.setAttributeValue(optionValueModel.getAttributeValue().trim()));
        List<String> nameModels = modelValues.stream().map(OptionValueModel::getAttributeValue).collect(Collectors.toList());
        Map<String, List<OptionValueModel>> nameModelsMap = modelValues.stream().collect(Collectors.groupingBy(OptionValueModel::getAttributeValue));

        List<ProductOptionValue> optionValues = persistenceOption.getProductOptionValues();
        List<String> optionNames = optionValues.stream().map(ProductOptionValue::getAttributeValue).collect(Collectors.toList());
        //新增的规格属性中不包含数据库中的属性 删除
        optionNames.forEach(optionName -> {
            if(!nameModels.contains(optionName)){
                productOptionValueRepository.deleteByProductOptionAndAttributeValue(finalPersistenceOption,optionName);
            }
        });

        //数据库中不包含新增的规格属性属性 添加
        List<String> newNames = new ArrayList<>();
        nameModels.forEach(name -> {
            if(!optionNames.contains(name)){
                newNames.add(name);
            }
        });

        //新增属性值    ps: 一个引用变量指向多个对象地址
        final ProductOptionValue[] productOptionValue = {null};
        newNames.forEach(name -> {
            productOptionValue[0] = new ProductOptionValue();
            OptionValueModel valueModel = nameModelsMap.get(name).get(0);
            newOptionValue(productOptionValue[0],finalPersistenceOption,valueModel);
        });

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    //@CacheEvict(value = "option:getOptionVlauesTree" , allEntries = true)
    public void deleteOption(Long optionId) {
        ProductOption productOption;

        Assert.notNull(productOption = productOptionRepository.findOne(optionId),"规格分类不存在");
        if(CollectionUtils.isNotEmpty(productOption.getProductOptionValues())){
            throw new IllegalArgumentException("请先删除规格属性");
        }
        productOptionRepository.delete(optionId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    //@CacheEvict(value = "option:getOptionVlauesTree" , allEntries = true)
    public void deleteOptionValue(Long optionValueId) {
        ProductOptionValue productOptionValue;
        productOptionValue = productOptionValueRepository.findOne(optionValueId);
        Assert.notNull(productOptionValue,"规格属性不存在");
        // 规格属性相关全部商品为空 , 可以删除规格属性
        List<SkuOptionValue> skuOptionValues = productOptionValue.getSkuOptionValues();
        Set optionValues = new HashSet();
        if(CollectionUtils.isNotEmpty(skuOptionValues)){
            skuOptionValues.stream().forEach(skuOptionValue -> {
                ProductSku productSku = skuOptionValue.getProductSku();
                Product product = productSku.getProduct();
                if(!Boolean.FALSE.equals(product.isArchived())){
                    optionValues.add(product.getProductName());
                }
            });
        }

        if(!optionValues.isEmpty()){
            throw new IllegalArgumentException(String.format("必须删除规格属性下的所有商品:{%s}",optionValues.toString()));
        }
        productOptionRepository.delete(optionValueId);

    }


    public ProductOptionValue newOptionValue(ProductOptionValue optionValue , ProductOption option, OptionValueModel optionValueModel) {
        optionValueModel.setAttributeValue(optionValueModel.getAttributeValue().trim());
        // 再次校验 保证不重复
        ProductOptionValue first = productOptionValueRepository.findFirstByAttributeValueAndProductOption(optionValueModel.getAttributeValue() , option);
        if(first==null){
            optionValue = new ProductOptionValue();
            BeanUtils.copyProperties(optionValueModel, optionValue);
            optionValue.setProductOption(option);
            return productOptionValueRepository.save(optionValue);
        }
       return null;
    }

    private OptionModel convertOptionMap(ProductOption productOption){

        OptionModel optionModel = new OptionModel();
        ArrayList<OptionValueModel> optionValueModels = new ArrayList<>();
        optionModel.setOptionValues(optionValueModels);

        BeanUtils.copyProperties(productOption,optionModel);
        productOption.getProductOptionValues().forEach(productOptionValue -> {
            OptionValueModel valueModel = new OptionValueModel();
            BeanUtils.copyProperties(productOptionValue,valueModel);
            optionValueModels.add(valueModel);
        });

        return optionModel;
    }
}
